package com.mapforge.gui.tools;

import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.Box;
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.JSeparator;

import com.mapforge.Constants;
import com.mapforge.gui.MapEditorMenuBar;
import com.mapforge.listener.MapToolChangeListener;
import com.mapforge.listener.TileMapCreationEvent;
import com.mapforge.listener.TileMapCreationListener;
import com.mapforge.map.tilewriter.RandomTileWriter;
import com.mapforge.map.tilewriter.RepeatingSequentialTileWriter;
import com.mapforge.map.tools.ZoomTool;
import com.mapforge.map.tools.selection.EllipseSelectionTool;
import com.mapforge.map.tools.selection.FloodFillSelectionTool;
import com.mapforge.map.tools.selection.RectangleSelectionTool;
import com.mapforge.map.tools.selection.SingleColumnSelectionTool;
import com.mapforge.map.tools.selection.SingleRowSelectionTool;
import com.mapforge.map.tools.tilewriting.AbstractTileWriterTool;
import com.mapforge.map.tools.tilewriting.EllipseTool;
import com.mapforge.map.tools.tilewriting.EraserTool;
import com.mapforge.map.tools.tilewriting.FloodFillTool;
import com.mapforge.map.tools.tilewriting.LineTool;
import com.mapforge.map.tools.tilewriting.PencilTool;
import com.mapforge.map.tools.tilewriting.RectangleTool;

/**
 * The {@link MapEditorToolPanel} class displays buttons representing map
 * editing tools.
 * 
 * @author Will Morrison
 * 
 */
public class MapEditorToolPanel extends JPanel implements
		TileMapCreationListener {
	/**
	 * Default serial version ID, here to remove warnings.
	 */
	private static final long serialVersionUID = 1L;

	// structures to hold buttons
	/**
	 * Holds all map tool buttons in this panel for ease of access
	 */
	private List<MapToolButton> mapToolButtons;

	/**
	 * Holds all tile writer buttons in this panel for ease of access
	 */
	private List<TileWriterButton> tileWriterButtons;

	// more specialed tools
	private ZoomTool zoomTool;

	// more specialized tool buttons
	private ZoomToolButton zoomToolButton;

	// tile writers
	private RepeatingSequentialTileWriter sequentialWriter;
	private RandomTileWriter randomWriter;

	// tile writing buttons
	private TileWriterButton sequentialWriterButton;
	private TileWriterButton randomWriterButton;

	// Tile writing tools
	private PencilTool pencilTool;
	private EraserTool eraserTool;
	private LineTool lineTool;
	private FloodFillTool floodFillTool;
	private RectangleTool rectangleTool;
	private EllipseTool ellipseTool;

	// tile writing tools buttons
	private TileWriterToolButton pencilButton;
	private TileWriterToolButton eraserButton;
	private TileWriterToolButton lineButton;
	private TileWriterToolButton floodFillButton;
	private TileWriterToolButton rectangleButton;
	private TileWriterToolButton ellipseButton;

	// Selection tools
	private FloodFillSelectionTool floodFillSelectionTool;
	private RectangleSelectionTool rectangleSelectionTool;
	private EllipseSelectionTool ellipseSelectionTool;
	private SingleRowSelectionTool singleRowSelectionTool;
	private SingleColumnSelectionTool singleColumnSelectionTool;

	// selection tool buttons
	private SelectionToolButton floodFillSelectionButton;
	private RectangleSelectionToolButton rectangleSelectionButton;
	private SelectionToolButton ellipseSelectionButton;
	private SelectionToolButton singleColumnSelectionButton;
	private SelectionToolButton singleRowSelectionButton;

	// button to represent selection tools
	// private CompositeMapToolPopupButton compositeSelectionToolButton;

	// button groups ensuring single selection of toggle buttons
	private ButtonGroup toolBtnGroup;
	private ButtonGroup tileWriterBtnGroup;

	JPanel previousToolPanel;
	private ActionListener toolsListener;

	public MapEditorToolPanel(MapEditorMenuBar menuBar) {
		super(new FlowLayout(FlowLayout.LEFT, 2, 2));

		toolsListener = new ToolsListener();

		// intialize data structures
		mapToolButtons = new ArrayList<MapToolButton>();
		tileWriterButtons = new ArrayList<TileWriterButton>();

		// initialize tile writer tools
		pencilTool = new PencilTool();
		eraserTool = new EraserTool();
		lineTool = new LineTool();
		floodFillTool = new FloodFillTool();
		rectangleTool = new RectangleTool();
		ellipseTool = new EllipseTool();

		// initialize selection tools
		floodFillSelectionTool = new FloodFillSelectionTool();
		rectangleSelectionTool = new RectangleSelectionTool();
		ellipseSelectionTool = new EllipseSelectionTool();
		singleRowSelectionTool = new SingleRowSelectionTool();
		singleColumnSelectionTool = new SingleColumnSelectionTool();

		// initialize specialized tools
		zoomTool = new ZoomTool();

		// init groups
		toolBtnGroup = new ButtonGroup();
		tileWriterBtnGroup = new ButtonGroup();

		// Init tilewriter buttons, creation method handles registering
		// w/buttongroup
		pencilButton = createTileWriterToolButton(Constants.PENCIL_ICON,
				pencilTool, toolBtnGroup);
		pencilButton.setMapToolPanel(null);
		eraserButton = createTileWriterToolButton(Constants.ERASER_ICON,
				eraserTool, toolBtnGroup);
		eraserButton.setMapToolPanel(new EraserToolControlPanel(eraserTool));
		lineButton = createTileWriterToolButton(Constants.LINE_ICON, lineTool,
				toolBtnGroup);
		lineButton.setMapToolCursor(Cursor
				.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
		lineButton.setMapToolPanel(null);
		floodFillButton = createTileWriterToolButton(Constants.FLOODFILL_ICON,
				floodFillTool, toolBtnGroup);
		floodFillButton.setMapToolPanel(null);
		rectangleButton = createTileWriterToolButton(Constants.RECTANGLE_ICON,
				rectangleTool, toolBtnGroup);
		rectangleButton.setMapToolCursor(Cursor
				.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
		ellipseButton = createTileWriterToolButton(Constants.ELLIPSE_ICON,
				ellipseTool, toolBtnGroup);
		ellipseButton.setMapToolCursor(Cursor
				.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));

		// init selection tool buttons
		floodFillSelectionButton = new SelectionToolButton(
				Constants.FLOODFILL_SELECTION_ICON, floodFillSelectionTool);
		floodFillSelectionButton.setMapToolPanel(null);
		rectangleSelectionButton = new RectangleSelectionToolButton(
				this.rectangleSelectionTool, menuBar);
		rectangleSelectionButton.setMapToolCursor(Cursor
				.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
		ellipseSelectionButton = new SelectionToolButton(
				Constants.ELLIPSE_SELECTION_ICON, ellipseSelectionTool);
		ellipseSelectionButton.setMapToolCursor(Cursor
				.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
		singleRowSelectionButton = new SelectionToolButton(
				Constants.SINGLE_ROW_SELECTION_ICON, singleRowSelectionTool);
		singleRowSelectionButton.setMapToolCursor(Cursor
				.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
		singleRowSelectionButton.setMapToolPanel(null);
		singleColumnSelectionButton = new SelectionToolButton(
				Constants.SINGLE_COLUMN_SELECTION_ICON,
				singleColumnSelectionTool);
		singleColumnSelectionButton.setMapToolCursor(Cursor
				.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
		singleColumnSelectionButton.setMapToolPanel(null);

		// init composite selection button
		/*
		 * MapToolButton[] selectionBtns = new MapToolButton[] {
		 * rectangleSelectionButton, ellipseSelectionButton,
		 * singleRowSelectionButton, singleColumnSelectionButton };
		 * compositeSelectionToolButton = new CompositeMapToolPopupButton(
		 * selectionBtns); compositeSelectionToolButton.setEnabled(false);
		 */

		// initialize specialized tool buttons
		zoomToolButton = new ZoomToolButton(zoomTool);
		zoomToolButton.setEnabled(false);

		// add tools to data structure
		mapToolButtons.add(pencilButton);
		mapToolButtons.add(eraserButton);
		mapToolButtons.add(lineButton);
		mapToolButtons.add(floodFillButton);
		mapToolButtons.add(rectangleButton);
		mapToolButtons.add(ellipseButton);
		mapToolButtons.add(zoomToolButton);
		// mapToolButtons.add(floodFillSelectionButton);
		// mapToolButtons.add(compositeSelectionToolButton);
		mapToolButtons.add(rectangleSelectionButton);
		// mapToolButtons.add(ellipseSelectionButton);
		// mapToolButtons.add(singleRowSelectionButton);
		// mapToolButtons.add(singleColumnSelectionButton);

		// initialize tile writers
		sequentialWriter = new RepeatingSequentialTileWriter();
		randomWriter = new RandomTileWriter();
		sequentialWriterButton = new TileWriterButton(sequentialWriter,
				Constants.TILEWRITE_SEQUENTIAL, "Sequential fill");
		randomWriterButton = new TileWriterButton(randomWriter,
				Constants.TILEWRITE_RANDOM, "Random fill");
		sequentialWriterButton.setEnabled(false);
		randomWriterButton.setEnabled(false);

		tileWriterButtons.add(sequentialWriterButton);
		tileWriterButtons.add(randomWriterButton);

		// add map editor buttons to panel, register as listeners to writer
		// buttons
		MapToolButton mapToolBtn;
		for (int i = 0; i < mapToolButtons.size(); i++) {
			mapToolBtn = mapToolButtons.get(i);
			add(mapToolBtn);
			mapToolBtn.addActionListener(toolsListener);
			if (mapToolBtn instanceof TileWriterToolButton) {
				TileWriterToolButton btn = (TileWriterToolButton) mapToolBtn;
				for (int j = 0; j < tileWriterButtons.size(); j++) {
					tileWriterButtons.get(j).addTileWriterChangeListener(btn);
				}
			}
		}

		toolBtnGroup.add(zoomToolButton);
		toolBtnGroup.add(floodFillSelectionButton);
		toolBtnGroup.add(rectangleSelectionButton);
		// toolBtnGroup.add(compositeSelectionToolButton);
		zoomToolButton.addActionListener(toolsListener);
		// add specialized map tools to panel
		add(zoomToolButton);

		add(Box.createHorizontalStrut(5));
		JSeparator separator = new JSeparator(JSeparator.VERTICAL);
		separator.setPreferredSize(new Dimension(1, 31));
		add(separator);
		add(Box.createHorizontalStrut(5));

		// add all tile writer buttons to panel
		for (int i = 0; i < tileWriterButtons.size(); i++) {
			tileWriterBtnGroup.add(tileWriterButtons.get(i));
			add(tileWriterButtons.get(i));
		}
		add(Box.createHorizontalStrut(10));
	}

	private TileWriterToolButton createTileWriterToolButton(ImageIcon icon,
			AbstractTileWriterTool tool, ButtonGroup group) {
		TileWriterToolButton btn = new TileWriterToolButton(icon, tool);
		btn.setEnabled(false);
		group.add(btn);
		return btn;
	}

	public void removeMapToolChangeListener(MapToolChangeListener listener) {
		for (int i = 0; i < mapToolButtons.size(); i++) {
			mapToolButtons.get(i).removeMapToolChangeListener(listener);
		}
	}

	public void addMapToolChangeListener(MapToolChangeListener listener) {
		for (int i = 0; i < mapToolButtons.size(); i++) {
			mapToolButtons.get(i).addMapToolChangeListener(listener);
		}
	}

	public ZoomToolButton getZoomToolButton() {
		return zoomToolButton;
	}

	/**
	 * 
	 * @return
	 */
	public List<MapToolButton> getMapToolButtons() {
		return mapToolButtons;
	}

	/**
	 * 
	 * @return
	 */
	public List<TileWriterButton> getTileWriterButtons() {
		return tileWriterButtons;
	}

	private void enableButtons(boolean value) {
		for (int i = 0; i < tileWriterButtons.size(); i++) {
			tileWriterButtons.get(i).setEnabled(value);
		}
		for (int i = 0; i < mapToolButtons.size(); i++) {
			mapToolButtons.get(i).setEnabled(value);
		}
	}

	/**
	 * Whenever a new map is created the bitmask on the tile writers needs to be
	 * updated.
	 */
	public void tileMapCreationPerformed(TileMapCreationEvent mapCreationEvent) {
		// TileMap map = mapCreationEvent.getTileMapCreated();
		enableButtons(true);
		// set all tile writers mask to the correct Mask
		// for (int i = 0; i < tileWriterButtons.size(); i++) {
		// tileWriterButtons.get(i).getTileWriter().setMask(map.getMask());
		// }
	}

	private class ToolsListener implements ActionListener {
		public void actionPerformed(ActionEvent e) {
			Object src = e.getSource();
			if (src instanceof MapToolButton) {
				MapToolButton btn = (MapToolButton) src;
				if (previousToolPanel != null) {
					remove(previousToolPanel);
				}
				previousToolPanel = btn.getMapToolPanel();
				if (previousToolPanel != null) {
					add(previousToolPanel);
				}
				revalidate();
				repaint();
			}
		}

	}
}
